package com.zerui.manager.openplan.gatewayimpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zerui.cola.dto.Response;
import com.zerui.manager.feign.handler.DeviceFeignHandler;
import com.zerui.manager.feign.request.DeviceActionExecuteRequest;
import com.zerui.manager.openplan.OpenPlan;
import com.zerui.manager.openplan.OpenPlanDevice;
import com.zerui.manager.openplan.OpenPlanImplement;
import com.zerui.manager.openplan.OpenPlanImplementTask;
import com.zerui.manager.openplan.convertor.OpenPlanConvert;
import com.zerui.manager.openplan.convertor.OpenPlanDeviceConvert;
import com.zerui.manager.openplan.convertor.OpenPlanImplementConvert;
import com.zerui.manager.openplan.entity.OpenPlanDeviceDo;
import com.zerui.manager.openplan.entity.OpenPlanDo;
import com.zerui.manager.openplan.entity.OpenPlanImplementDo;
import com.zerui.manager.openplan.gateway.OpenPlanGateWay;
import com.zerui.manager.openplan.mapper.OpenPlanDeviceMapper;
import com.zerui.manager.openplan.mapper.OpenPlanImplementMapper;
import com.zerui.manager.openplan.mapper.OpenPlanMapper;
import com.zerui.manager.web.cmd.OpenPlanDeviceAddCmd;
import com.zerui.manager.web.cmd.OpenPlanQryCmd;
import com.zerui.manager.web.enums.DeviceOperateEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author wh
 * @create_time 2023-08-23 15:28
 */
@Component
@Slf4j
public class OpenPlanGateWayImpl implements OpenPlanGateWay {

	@Resource
	private OpenPlanMapper openPlanMapper;
	@Resource
	private OpenPlanImplementMapper openPlanImplementMapper;
	@Resource
	private OpenPlanDeviceMapper openPlanDeviceMapper;
	@Resource
	private DeviceFeignHandler deviceFeignHandler;


	@Override
	public Response addOpenPlan(OpenPlan openPlan) {
		OpenPlanDo openPlanDo = OpenPlanConvert.INSTANCE.convertOpenPlanToOpenPlanDo(openPlan);
		openPlanMapper.insert(openPlanDo);
		return Response.buildSuccess();
	}

	@Override
	public OpenPlan selectById(Long id) {
		OpenPlanDo openPlanDo = openPlanMapper.selectById(id);
		return OpenPlanConvert.INSTANCE.convertOpenPlanDoToOpenPlan(openPlanDo);
	}

	@Override
	public Response updateById(OpenPlan openPlan) {
		OpenPlanDo openPlanDo = OpenPlanConvert.INSTANCE.convertOpenPlanToOpenPlanDo(openPlan);
		openPlanMapper.updateById(openPlanDo);
		return Response.buildSuccess();
	}

	@Override
	public Response deleteById(Long id) {
		openPlanMapper.deleteById(id);
		return Response.buildSuccess();
	}

	@Override
	public Page<OpenPlan> getPageList(OpenPlanQryCmd openPlanQryCmd) {
		LambdaQueryWrapper<OpenPlanDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(ObjectUtils.isNotEmpty(openPlanQryCmd.getAccept()),OpenPlanDo::getAccept,openPlanQryCmd.getAccept());
		queryWrapper.like(StringUtils.isNotBlank(openPlanQryCmd.getName()),OpenPlanDo::getName,openPlanQryCmd.getName());
		Page<OpenPlanDo> page = new Page<>(openPlanQryCmd.getPageIndex(),openPlanQryCmd.getPageSize());
		Page<OpenPlanDo> selectPage = openPlanMapper.selectPage(page, queryWrapper);
		return OpenPlanConvert.INSTANCE.convertOpenPlanDoToOpenPlanPage(selectPage);
	}

	@Override
	public void addBatchImplements(List<OpenPlanImplement> implementList) {
		List<OpenPlanImplementDo> planImplementDos = OpenPlanImplementConvert.INSTANCE.convertOpenPlanImplementToOpenPlanImplementDo(implementList);
		openPlanImplementMapper.insertBatchSomeColumn(planImplementDos);
	}

	@Override
	public void deleteImplementByPlanId(Long openPlanId) {
		LambdaQueryWrapper<OpenPlanImplementDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanImplementDo::getOpenPlanId,openPlanId);
		openPlanImplementMapper.delete(queryWrapper);
	}

	@Override
	public void executeTask(Long implementId) {
		log.info("计划开始执行implementId：{}",implementId);
		OpenPlanImplementDo openPlanImplementDo = openPlanImplementMapper.selectById(implementId);
		if(ObjectUtils.isNotEmpty(openPlanImplementDo) && !openPlanImplementDo.getImplement()){
			//查询绑定的所有设备
			List<Long> deviceIds = selectDeviceIds(openPlanImplementDo.getOpenPlanId());
			if(CollectionUtils.isEmpty(deviceIds)){
				return;
			}
			Integer operation = openPlanImplementDo.getOperation();
			String action = (operation == 1 ) ? DeviceOperateEnum.NORMALLY_OPEN.getAction() : DeviceOperateEnum.NORMALLY_CLOSE.getAction() ;
			List<DeviceActionExecuteRequest> requests = new ArrayList<>();

			deviceIds.forEach(e-> requests.add(DeviceActionExecuteRequest.builder()
					.id(e.toString())
					.actions(createAction(action))
					.build()));
			openPlanImplementDo.setImplement(true);
			openPlanImplementMapper.updateById(openPlanImplementDo);
			deviceFeignHandler.batchActionExecute(requests);
		}
	}

	@Override
	public List<OpenPlanImplementTask> selectImplementByTime(String now) {
		//查询当天且没有执行的开门implement
		LambdaQueryWrapper<OpenPlanImplementDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanImplementDo::getImplement,false);
		queryWrapper.like(OpenPlanImplementDo::getOperationTime,now);
		List<OpenPlanImplementDo> implementDos = openPlanImplementMapper.selectList(queryWrapper);
		List<OpenPlanImplementTask> tasks = new ArrayList<>();
		if(CollectionUtils.isNotEmpty(implementDos)){
			implementDos.forEach(e-> tasks.add(OpenPlanImplementTask.builder()
					.id(e.getId())
					.operationTime(e.getOperationTime())
					.build()));
		}

		return tasks;
	}

	@Override
	public Map<Long, Long> getOpenPlanDeviceMapById(List<Long> deviceIds) {
		LambdaQueryWrapper<OpenPlanDeviceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(OpenPlanDeviceDo::getDeviceId,deviceIds);
		List<OpenPlanDeviceDo> deviceDos = openPlanDeviceMapper.selectList(queryWrapper);
		if(CollectionUtils.isNotEmpty(deviceDos)){
			return deviceDos.stream()
					.collect(Collectors.toMap(OpenPlanDeviceDo::getDeviceId,OpenPlanDeviceDo::getOpenPlanId));
		}
		return Collections.emptyMap();
	}

	@Override
	public void addBatchOpenPlanDevice(List<OpenPlanDevice> openPlanDevices) {
		List<OpenPlanDeviceDo> openPlanDeviceDos = OpenPlanDeviceConvert.INSTANCE.convertOpenPlanDeviceDoToOpenPlanDevice(openPlanDevices);
		openPlanDeviceMapper.insertBatchSomeColumn(openPlanDeviceDos);
	}

	@Override
	public Response deleteOpenPlanDevice(OpenPlanDeviceAddCmd openPlanDeviceAddCmd) {
		LambdaQueryWrapper<OpenPlanDeviceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanDeviceDo::getOpenPlanId,openPlanDeviceAddCmd.getPlanId());
		queryWrapper.in(OpenPlanDeviceDo::getDeviceId,openPlanDeviceAddCmd.getDeviceIds());
		openPlanDeviceMapper.delete(queryWrapper);
		return Response.buildSuccess();
	}

	@Override
	public void deleteDeviceByPlanId(Long id) {
		LambdaQueryWrapper<OpenPlanDeviceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanDeviceDo::getOpenPlanId,id);
		openPlanDeviceMapper.delete(queryWrapper);
	}

	@Override
	public List<OpenPlanImplement> selectImplementById(Long id) {
		LambdaQueryWrapper<OpenPlanImplementDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanImplementDo::getOpenPlanId,id);
		queryWrapper.eq(OpenPlanImplementDo::getImplement,false);
		List<OpenPlanImplementDo> openPlanImplementDos = openPlanImplementMapper.selectList(queryWrapper);
		return OpenPlanImplementConvert.INSTANCE.convertOpenPlanImplementDoToOpenPlanImplement(openPlanImplementDos);
	}

	@Override
	public void deleteDeviceById(Long deviceId) {
		LambdaQueryWrapper<OpenPlanDeviceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanDeviceDo::getDeviceId,deviceId);
		openPlanDeviceMapper.delete(queryWrapper);
	}


	private List<Long> selectDeviceIds(Long openPlanId) {
		LambdaQueryWrapper<OpenPlanDeviceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(OpenPlanDeviceDo::getOpenPlanId,openPlanId);
		List<OpenPlanDeviceDo> deviceDos = openPlanDeviceMapper.selectList(queryWrapper);
		return deviceDos.stream().map(OpenPlanDeviceDo::getDeviceId).collect(Collectors.toList());
	}
	private Map<String, Map<String, Object>> createAction(String action) {
		Map<String, Map<String, Object>> map = new HashMap<>();
		map.put(action,new HashMap<>());
		return map;
	}

}
